#define DECISION_INNET     0
#define DECISION_BASE      1
#define DECISION_THRESHOLD 100            // how much the cost of in-net should exceed Base
                                          // to decide to join at Base (in-net can be improved)

#define COSTBUFFER_SIZE             20

#define GROUPOPT_NONE               0
#define GROUPOPT_TYPE1              1
#define GROUPOPT_TYPE2              2

typedef struct {
  uint8_t plancost_seq;
  int plancost_diff;
} PACKING_MACRO COORD_COST;

typedef struct {
  uint8_t cmd;

  uint8_t query_id;
  uint8_t node_count;
  struct {
    ADDRESS id;
    COORD_COST cost;
  } PACKING_MACRO nodes[COSTBUFFER_SIZE];
} PACKING_MACRO COORDCOST_MSGHI;

typedef struct {
  uint8_t decision;
  uint8_t decision_seq;
} PACKING_MACRO COORD_DECISION;

typedef struct {
  uint8_t cmd;

  uint8_t query_id;
  uint8_t forward_decision;
  COORD_DECISION decision;
} PACKING_MACRO COORDDECISION_MSGHI;

typedef struct {
  uint8_t cmd;

  uint8_t query_id;
  uint8_t source_count;
  ADDRESS source_nodes[COSTBUFFER_SIZE];
  uint8_t target_count;
  ADDRESS target_nodes[COSTBUFFER_SIZE];

  uint8_t remove_pairs;  // if set will remove pairs instead of adding them
} PACKING_MACRO COORDPAIRS_MSGHI;

typedef struct {           // cached costs of nodes in the same group
  uint8_t used;

  ADDRESS node_id, source_id; // node_id - to which node the cost applies, source_id - which node we got the cost from
  COORD_COST cost;          // latest cost received
  COORD_DECISION decision;  // latest unique decision sent
} PACKING_MACRO COSTBUFFER_ENTRY;

typedef struct {
  COSTBUFFER_ENTRY cost_buffer[COSTBUFFER_SIZE];  // group optimization structures
  uint8_t cost_updated, coordinator_updated, cost_received;
  int localcoordinator_index;  // index of local coordinator node in source buffer
  ADDRESS globalcoordinator_node;
  uint8_t decision, rcv_decisionseq, sent_decisionseq;  // last decision, latest send and received decision sequence numbers
} PACKING_MACRO GROUPOPT_ENTRY;

void handle_coordcostmsghi(ADDRESS source_node, ADDRESS dest_node, uint8_t path_nodecount,
  ADDRESS *path_nodes, uint8_t data_len, uint8_t *data);
void handle_coorddecisionmsghi(ADDRESS source_node, ADDRESS dest_node, uint8_t path_nodecount,
  ADDRESS *path_nodes, uint8_t data_len, uint8_t *data);
void handle_coordpairsmsghi(ADDRESS source_node, ADDRESS dest_node, uint8_t path_nodecount,
  ADDRESS *path_nodes, uint8_t data_len, uint8_t *data);

void group_opt(uint8_t query_id, int source_index);
void groupopt_coordcost(uint8_t query_id);
void groupopt_coorddecision(uint8_t query_id);
uint8_t check_decisionpending();


